/***************************************************************************
 *   Copyright (C) 2011  by TinySofts                                      *
 *   tinysofts@gmail.com                                                   *
 *   All Rights Reserved.                                                  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   Refer to http://code.google.com/p/tinydict/                           *
 ***************************************************************************/
/*
    DB Functions
    Status: Open;ReleaseReady;L
*/

#include <QtSql/QSqlError>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include "tdict.h"

/*Initialize `words` Table*/
int initTinyDictWords(QString & info )
{
    QSqlQuery query;
    query.prepare("DROP TABLE IF EXISTS words");
    bool res = query.exec();
    info = "Words;";
    if(!res)
    {
        info+=query.lastError().text();
        return -1; /*Drop Table Error*/
    }
    query.prepare("CREATE TABLE words ("
                "word varchar(256) PRIMARY KEY,"
                "explanation blob"
                ")");
    res = query.exec();
    if(!res)
    {
        info+=query.lastError().text();
        return -2; /*Create Table Error*/
    }

    return 0;
}


/*Initalize `config` Table*/
int initTinyDictConfig(QString & info)
{
    QSqlQuery query;
    query.prepare("DROP TABLE IF EXISTS config");
    bool res = query.exec();
    info = "DictConfig;";
    if(!res)
    {
        info+=query.lastError().text();
        return -1; /*DROP ERROR*/
    }
    query.prepare("CREATE TABLE config ("
                  "k char(16) primary key,"
                  "v char(64)"
                  " )");
    res = query.exec();
    if(!res) {
        info+=query.lastError().text();
        return -2; /*CREATE TABLE ERROR*/
    }
    query.prepare("INSERT INTO config VALUES (:k,:v)");
    query.bindValue(":k","magic");
    query.bindValue(":v","0xWXYXRHY0x");
    res = query.exec();
    if(!res) {
        info+=query.lastError().text();
        return -3; /*INSERT TABLE ERROR*/
    }
    return 0;
}

/*Initialize `dictinfo` Table*/
int initDictInfo(QString & info )
{
    QSqlQuery query;
    query.prepare("DROP TABLE IF EXISTS dictinfo");
    bool res = query.exec();
    info ="DictInfo;";
    if(res)
    {
        query.prepare("CREATE TABLE dictinfo ("
                      "seq int primary key,"
                      "type int default 0,"
                      "dictname char(64),"
                      "dictpath vchar(256),"
                      "filename vchar(256),"
                      "wordcount int,"
                      "version vchar(64)"
                      " )");
        res = query.exec();
        if(!res) {
            return -1;
        }
        else {
            info += query.lastError().text();
        }
        query.prepare("INSERT INTO dictinfo (seq) VALUES (0)");
        res = query.exec();
        if(!res) {
            return -2;
        }
        else {
            info += query.lastError().text();
        }
    }
    else
    {
        info = query.lastError().text();
    }
    return 0;
}

/*Initialize TinyDict DataBase*/
int initTinyDictTables(QString & info )
{
    initTinyDictWords(info);
    initDictInfo(info);
    initTinyDictConfig(info);
    return 0;
}

/*Initialize `babylon` Table*/
int initBabylonTable(QString &info)
{
    QSqlQuery query;
    query.prepare("DROP TABLE IF EXISTS babylon");
    bool res = query.exec();
    info = "Babylon;";
    if(res)
    {
        query.prepare("CREATE TABLE babylon ("
                      "dictseq int,"
                      "dictname char(256),"
                      "word char(128),"
                      "definition blob"
                      ")");
        res = query.exec();
        if(!res) {
            info += query.lastError().text();
            return -1;
        }
        return 0;
    }
    else
    {
        info += query.lastError().text();
        return -2;
    }
}


/*Generate `words` Table from StarDict*/
int genTinyDictDB(QString path, QString filename)
{
    TDict dict;
    bool res = dict.setPath(path,filename);
    if(!res){
        return -1000; /*Init Dict Error*/
    }
    QString info;
    int r=initTinyDictWords(info);
    if( r<0) {
        return r; /*Initialize `words` Error*/
    }

    const int BATCH = 5000;
    int c=0;
    int offset=0,size=0;
    int batch = dict.wordNum/BATCH;
    QSqlQuery query;
    for(int b=0;b<batch;b++)
    {
        QVariantList wds;
        QVariantList eps;
        QSqlDatabase::database().transaction();
        query.prepare("INSERT INTO words (word, explanation) VALUES(?,?)");
        for(int i=0;i<BATCH;i++)
        {
            int s = b*BATCH+i;
            wds << dict.getWord(s,offset,size);
            eps << qCompress(dict.readDict(offset,size));
        }
        query.addBindValue(wds);
        query.addBindValue(eps);
        res = query.execBatch();
        QSqlDatabase::database().commit();
        if(!res) {
            return -11; /*Batch Commit Error*/
        }
    }
    QSqlDatabase::database().transaction();
    for(int i=batch*BATCH;i<dict.wordNum;i++) {
        QString word = dict.getWord(i,offset,size);
        QByteArray exp = dict.readDict(offset,size);
        query.prepare("INSERT INTO words (word, explanation) VALUES(:w,:e)");
        query.bindValue(":w",word);
        query.bindValue(":e",qCompress(exp));
        res = query.exec();
        c++;
        if(!res)
        {
            return -c; /*Left Commit Error*/
        }
    }
    QSqlDatabase::database().commit();
    return dict.wordNum;
}

/*Add word(w,e) to `words`*/
int add2TinyDictDB(QString w, QString e)
{
    QSqlQuery query;
    query.prepare("SELECT explanation FROM words WHERE word=:w");
    query.bindValue(":w",w);
    bool res = query.exec();
    if(!res)
    {
        return -1; /*SELECT ERROR*/
    }
    if(query.next())
    {
        QByteArray exp;
        exp.append(query.value(0).toString()+"\r\n");
        exp.append(e);
        query.prepare("UPDATE words SET explanation=:e WHERE word=:w");
        query.bindValue(":w",w);
        query.bindValue(":e",qCompress(exp));
        res = query.exec();
        if(!res)
        {
            return -2; /*Update Error*/
        }
        return 1; /*UPDATE OK*/
    }
    else
    {
        QByteArray exp;
        exp.append(e);
        query.prepare("INSERT INTO words (word, explanation) VALUES(:w,:e)");
        query.bindValue(":w",w);
        query.bindValue(":e",qCompress(exp));
        res = query.exec();
        if(!res)
        {
            return -3; /*Insert Table Error*/
        }
        return 2; /*INSERT OK*/
    }
    return 0;
}


#include "babylondict.h"
int ExtractBabylonDict(int dictseq, BabylonDict & b)
{
    int count=0;
    bgl_entry e;
    QTextCodec *codec = QTextCodec::codecForName("GBK");
    if(codec==0) {
        return -10; //codec error
    }
    b.read();
    QString title(b.title().c_str());
    QSqlQuery query;
    QVariantList sqs;
    QVariantList nms;
    QVariantList wds;
    QVariantList eps;
    QSqlDatabase::database().transaction();
    query.prepare("INSERT INTO babylon (dictseq, dictname, word, definition) "
                  "VALUES(?,?,?,?)");
    for(;;)
    {
        e = b.readEntry();
        if(e.headword.empty())
            break;
        QString w(e.headword.c_str());
        QString r=codec->toUnicode(e.definition.c_str());
        sqs<<dictseq; 
        nms<<title;
        wds<<w;
        eps<<r;
        count++;
    }
    query.addBindValue(sqs);
    query.addBindValue(nms);
    query.addBindValue(wds);
    query.addBindValue(eps);
    bool res = query.execBatch();
    QSqlDatabase::database().commit();
    if(!res) {
        return -11; /*Batch Commit Error*/
    }
    QSqlDatabase::database().commit();
    return count;
}


QByteArray getBabylonDef(int dictseq, QString word)
{
    QByteArray def("");;
    QString w = word.trimmed();
    if(w=="") {
        return def;
    }
    QSqlQuery query;
    query.prepare("SELECT definition,word FROM babylon "
                  "WHERE dictseq=:seq AND word <=:w ORDER BY word DESC");
    query.bindValue(":w", w);
    query.bindValue(":seq",dictseq);
    bool res = query.exec();
    if(res)
    {
        res = query.next();
        if(res) {
            QByteArray bytes = query.value(0).toByteArray();
            def.append(query.value(1).toString());
            def.append("\r\n");
            def.append(bytes);
            return def;
        }
        else {
            def.append(word);
        }
    }
    else
    {
    }
    return def;
}

int delBabylonDict(int dictseq)
{
    QSqlQuery query;
    query.prepare("DELETE FROM babylon "
                  "WHERE dictseq=:seq");
    query.bindValue(":seq",dictseq);
    bool res = query.exec();
    if(res)
    {
        return 0;
    }
    else
    {
        return -1;
    }
}
